package session.stateless;

import entity.AddressEntity;
import entity.BranchEntity;
import entity.FnBBranchEntity;
import entity.OperatingHoursEntity;
import entity.CuisineTypeEntity;
import entity.ExtendedOperatingHoursEntity;
import entity.OperatingHoursRemarksEntity;
import entity.StakeholderEntity;
import java.util.List;
import javax.ejb.Stateless;
import javax.ejb.LocalBean;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import util.enumhelper.OperatingHrs;
import util.enumeration.CuisineType;
import util.enumeration.FnbType;
import exception.ExistException;
import javax.persistence.Query;
import util.enumeration.IsHalal;
import util.enumeration.Language;
import util.enumeration.PriceRange;

@Stateless
@LocalBean
public class BranchSessionBean {

    @PersistenceContext
    private EntityManager entityManager;

    /*-------------------------------------------------------------------------*/
    /*------------------------------ Add Branch--------------------------------*/
    /*-------------------------------------------------------------------------*/
    public boolean addBranch(String branchName, int postalCode, String unitNumber, String blkNumber,
            String streetName, String buildingName, String contactNumber,
            String contactPerson, String emailAddress, FnbType fnbTypeEnum, IsHalal isHalalEnum, PriceRange priceRangeEnum, String locale, String operatingHoursRemarks,
            List<CuisineType> selectedCuisine, List<OperatingHrs> operatingHrsList, List<OperatingHrs> extendedOperatingHrsList, StakeholderEntity stakeholder) throws ExistException {

        try {
            
            
            //Add Branch address
            AddressEntity branchAddress = new AddressEntity();
            branchAddress.setPostalCode(postalCode);
            branchAddress.setUnitNumber(unitNumber);
            branchAddress.setBlkNumber(blkNumber);
            branchAddress.setStreetName(streetName);
            branchAddress.setBuildingName(buildingName);
            entityManager.persist(branchAddress);
            entityManager.flush();


            //Add FnB BranchEntity
            FnBBranchEntity FnB = new FnBBranchEntity();
            FnB.setBranchName(branchName);
            FnB.setContactPerson(contactPerson);
            FnB.setContactNumber(contactNumber);
            FnB.setBranchAddress(branchAddress);
            FnB.setEmailAddress(emailAddress);
            FnB.setIsHalal(isHalalEnum);
            FnB.setFnBType(fnbTypeEnum);
            FnB.setPriceRange(priceRangeEnum);
            FnB.setStakeholder(stakeholder);
            entityManager.persist(FnB);
            entityManager.flush();

            //Add Branch Operating Hours
            for (int i = 0; i < operatingHrsList.size(); i++) {
                OperatingHoursEntity operatingHours = new OperatingHoursEntity();
                operatingHours.setBranch(FnB);
                operatingHours.setOperatingDay(operatingHrsList.get(i).getOperatingDay());
                operatingHours.setOperatingDayEnum(operatingHrsList.get(i).getOperatingDayEnum());
                operatingHours.setOpeningHoursEnum(operatingHrsList.get(i).getOpeningHoursEnum());
                operatingHours.setOpeningHours(operatingHrsList.get(i).getOpeningHours());
                operatingHours.setClosingHoursEnum(operatingHrsList.get(i).getClosingHoursEnum());
                operatingHours.setClosingHours(operatingHrsList.get(i).getClosingHours());
                entityManager.persist(operatingHours);
                entityManager.flush();
            }

            //Add Branch Extended Operating Hours
            for (int i = 0; i < extendedOperatingHrsList.size(); i++) {
                ExtendedOperatingHoursEntity extendedOperatingHours = new ExtendedOperatingHoursEntity();
                extendedOperatingHours.setBranch(FnB);
                extendedOperatingHours.setOperatingDay(extendedOperatingHrsList.get(i).getOperatingDay());
                extendedOperatingHours.setOperatingDayEnum(extendedOperatingHrsList.get(i).getOperatingDayEnum());
                extendedOperatingHours.setOpeningHoursEnum(extendedOperatingHrsList.get(i).getOpeningHoursEnum());
                extendedOperatingHours.setOpeningHours(extendedOperatingHrsList.get(i).getOpeningHours());
                extendedOperatingHours.setClosingHoursEnum(extendedOperatingHrsList.get(i).getClosingHoursEnum());
                extendedOperatingHours.setClosingHours(extendedOperatingHrsList.get(i).getClosingHours());
                extendedOperatingHours.setSpecificDate(extendedOperatingHrsList.get(i).getSpecificDate());
                entityManager.persist(extendedOperatingHours);
                entityManager.flush();
            }

            OperatingHoursRemarksEntity opHoursRemarks = new OperatingHoursRemarksEntity();
            opHoursRemarks.setRemarks(operatingHoursRemarks);
            opHoursRemarks.setLocale(locale);
            opHoursRemarks.setBranch(FnB);
            entityManager.persist(opHoursRemarks);
            entityManager.flush();


            //Add Cuisine Pref
            for (int i = 0; i < selectedCuisine.size(); i++) {
                CuisineTypeEntity cp = new CuisineTypeEntity();
                CuisineType selectCuisineType = (CuisineType) selectedCuisine.get(i);
                cp.setCuisineType(selectCuisineType);
                cp.setFnbBranch(FnB);
                entityManager.persist(cp);
                entityManager.flush();
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    /*-------------------------------------------------------------------------------*/
    /*------------------------------ Edit Branch ------------------------------------*/
    /*-------------------------------------------------------------------------------*/
    public boolean editBranchDetails(FnBBranchEntity fnbBranch,
            AddressEntity branchAddress, String branchName, int postalCode, String blkNumber,
            String streetName, String unitNumber, String buildingName, String contactNumber,
            String contactPerson, String emailAddress, FnbType fnbTypeEnum, IsHalal isHalalEnum, PriceRange priceRangeEnum, String locale, String operatingHoursRemarks,
            List<CuisineType> cuisineTypeList, List<OperatingHrs> operatingHrsList, List<OperatingHrs> extendedOperatingHrsList) {


        AddressEntity branchAddr = entityManager.find(AddressEntity.class, branchAddress.getId());
        if (branchAddr == null) {
            return false;
        }
        //values taken from edit managedbean
        branchAddr.setBuildingName(buildingName);
        branchAddr.setBlkNumber(blkNumber);
        branchAddr.setPostalCode(postalCode);
        branchAddr.setStreetName(streetName);
        branchAddr.setUnitNumber(unitNumber);
        entityManager.persist(branchAddr);

        FnBBranchEntity fnBBranch = entityManager.find(FnBBranchEntity.class, fnbBranch.getId());
        if (fnBBranch == null) {
            return false;
        }
        //values taken from edit managedbean
        fnBBranch.setPriceRange(priceRangeEnum);
        fnBBranch.setIsHalal(isHalalEnum);
        fnBBranch.setFnBType(fnbTypeEnum);
        fnBBranch.setBranchName(branchName);
        fnBBranch.setContactNumber(contactNumber);
        fnBBranch.setContactPerson(contactPerson);
        fnBBranch.setEmailAddress(emailAddress);
        entityManager.persist(fnBBranch);


        //--Remove all operating hours in database of the same FnB branch before re-adding--
        //Select all records of the same branch in OperatingHoursEntity
        List<OperatingHoursEntity> operatingHrsEntityList = viewBranchOperatingHours(fnbBranch.getId());
        for (int i = 0; i < operatingHrsEntityList.size(); i++) {
            OperatingHoursEntity branchOpHours = entityManager.find(OperatingHoursEntity.class, operatingHrsEntityList.get(i).getId());
            if (branchOpHours != null) {
                //delete records
                entityManager.remove(branchOpHours);
            }
        }
        //Add Branch Operating Hours
        for (int i = 0; i < operatingHrsList.size(); i++) {
            OperatingHoursEntity operatingHours = new OperatingHoursEntity();
            operatingHours.setBranch(fnBBranch);
            operatingHours.setOperatingDay(operatingHrsList.get(i).getOperatingDay());
            operatingHours.setOperatingDayEnum(operatingHrsList.get(i).getOperatingDayEnum());
            operatingHours.setOpeningHoursEnum(operatingHrsList.get(i).getOpeningHoursEnum());
            operatingHours.setOpeningHours(operatingHrsList.get(i).getOpeningHours());
            operatingHours.setClosingHoursEnum(operatingHrsList.get(i).getClosingHoursEnum());
            operatingHours.setClosingHours(operatingHrsList.get(i).getClosingHours());
            entityManager.persist(operatingHours);
            entityManager.flush();
        }

        //comments
        OperatingHoursRemarksEntity opHoursRemarks = viewOperatingHoursRemarks(locale, fnBBranch.getId());
        if (opHoursRemarks.getLocale().isEmpty()) {
            //If there is no record, create a new entity and add it into database
            OperatingHoursRemarksEntity opHrsRemarks = new OperatingHoursRemarksEntity();
            opHrsRemarks.setRemarks(operatingHoursRemarks);
            opHrsRemarks.setLocale(locale);
            opHrsRemarks.setBranch(fnBBranch);
            entityManager.persist(opHrsRemarks);
        } else {
            //if record exist, replace the remarks and save into database
            opHoursRemarks.setRemarks(operatingHoursRemarks);
            opHoursRemarks.setLocale(locale);
            entityManager.persist(opHoursRemarks);
        }

        //--Remove all cuisinePref in database of the same FnB branch before re-adding--
        //Select all records of the same branch in cuisine type entity
        List<CuisineTypeEntity> cuisinePref = viewCuisinePref(fnbBranch.getId());
        for (int i = 0; i < cuisinePref.size(); i++) {
            CuisineTypeEntity cuisinePreference = entityManager.find(CuisineTypeEntity.class, cuisinePref.get(i).getId());
            if (cuisinePreference != null) {
                entityManager.remove(cuisinePreference);
            }
        }

        //Add back all selected cuisine types into database after deleting all cuisine type of the same branch
        for (int i = 0; i < cuisineTypeList.size(); i++) {
            CuisineTypeEntity cp = new CuisineTypeEntity();
            cp.setCuisineType(cuisineTypeList.get(i));
            //cp.setCuisineType(cuisineTypeList.get(i).toString());
            cp.setFnbBranch(fnbBranch);
            entityManager.persist(cp);
        }


        //--Remove all extendedOperatingHrsEntityList in database of the same branch before re-adding--
        //Select all records of the same branch in extended operating hours entity
        List<ExtendedOperatingHoursEntity> extendedOperatingHrsEntityList = viewExtendedOperatingHours(fnbBranch.getId());
        for (int i = 0; i < extendedOperatingHrsEntityList.size(); i++) {
            ExtendedOperatingHoursEntity extendedOp = entityManager.find(ExtendedOperatingHoursEntity.class, extendedOperatingHrsEntityList.get(i).getId());
            //OperatingHoursEntity ophrEntity = entityManager.find(OperatingHoursEntity.class, extendedOperatingHrsEntityList.get(i).getId());
            if (extendedOp != null) {
                //delete records
                entityManager.remove(extendedOp);
            }
        }

        //Add back all the extended operating hours into database after deleting all of them of the same branch
        for (int i = 0; i < extendedOperatingHrsList.size(); i++) {
            ExtendedOperatingHoursEntity extendedOpHrEntity = new ExtendedOperatingHoursEntity();
            extendedOpHrEntity.setOperatingDay(extendedOperatingHrsList.get(i).getOperatingDay());
            extendedOpHrEntity.setOperatingDayEnum(extendedOperatingHrsList.get(i).getOperatingDayEnum());
            extendedOpHrEntity.setOpeningHoursEnum(extendedOperatingHrsList.get(i).getOpeningHoursEnum());
            extendedOpHrEntity.setOpeningHours(extendedOperatingHrsList.get(i).getOpeningHours());
            extendedOpHrEntity.setClosingHoursEnum(extendedOperatingHrsList.get(i).getClosingHoursEnum());
            extendedOpHrEntity.setClosingHours(extendedOperatingHrsList.get(i).getClosingHours());
            extendedOpHrEntity.setSpecificDate(extendedOperatingHrsList.get(i).getSpecificDate());
            extendedOpHrEntity.setBranch(fnBBranch);
            entityManager.persist(extendedOpHrEntity);
        }

        return true;
    }

    /*--------------------------------------------------------------------------------------*/
    /*------------------------------ Delete BranchEntity -----------------------------------*/
    /*--------------------------------------------------------------------------------------*/
    public boolean deleteBranchDetails(FnBBranchEntity fnbBranch, List<CuisineTypeEntity> cuisinePref, List<OperatingHoursEntity> branchOperatingHours, AddressEntity branchAddress, List<ExtendedOperatingHoursEntity> extendedOperatingHours) throws ExistException {

        for (int i = 0; i < cuisinePref.size(); i++) {
            CuisineTypeEntity cuisinePreference = entityManager.find(CuisineTypeEntity.class, cuisinePref.get(i).getId());
            if (cuisinePreference != null) {
                entityManager.remove(cuisinePreference);
            }
        }

        for (int i = 0; i < extendedOperatingHours.size(); i++) {
            ExtendedOperatingHoursEntity extendedOperating = entityManager.find(ExtendedOperatingHoursEntity.class, extendedOperatingHours.get(i).getId());
            if (extendedOperating != null) {
                entityManager.remove(extendedOperating);
            }
        }

        for (int i = 0; i <= Language.values().length; i++) {
            OperatingHoursRemarksEntity operatingHoursRemarks = entityManager.find(OperatingHoursRemarksEntity.class, fnbBranch.getId());
            if (operatingHoursRemarks != null) {
                entityManager.remove(operatingHoursRemarks);
            }
        }


        for (int i = 0; i < branchOperatingHours.size(); i++) {
            OperatingHoursEntity branchOpHours = entityManager.find(OperatingHoursEntity.class, branchOperatingHours.get(i).getId());
            if (branchOpHours != null) {
                entityManager.remove(branchOpHours);
            }
        }

        FnBBranchEntity fnBBranch = entityManager.find(FnBBranchEntity.class, fnbBranch.getId());
        if (fnBBranch != null) {
            //entityManager.remove(entityManager.merge(fnBBranch));
            entityManager.remove(fnBBranch);
        }

        AddressEntity branchAddr = entityManager.find(AddressEntity.class, branchAddress.getId());
        if (branchAddr != null) {
            entityManager.remove(branchAddr);
        }
        return true;
    }

    public List<FnBBranchEntity> getFnBBranchList() {
        Query query = entityManager.createQuery("SELECT r FROM FnBBranch r");
        return query.getResultList();
    }

    //**********************************************************************//
    //********* Still need to change to select branch by stakeholder *******//
    //**********************************************************************//
    public List<FnBBranchEntity> viewAllFnBBranch(Long stakeholderId) {
        Query query = entityManager.createQuery("SELECT fnbB FROM FnBBranch fnbB, Branch b where b.stakeholder.id =:stakeholderId AND b = fnbb");
        query.setParameter("stakeholderId", stakeholderId);
        return query.getResultList();
    }

    public List<BranchEntity> getAllBranch(Long stakeholderId) {
        StakeholderEntity stakeholder = entityManager.find(StakeholderEntity.class, stakeholderId);
        return stakeholder.getBranches();
    }

    //====================== Selection from database with branch ======================//
    public AddressEntity viewBranchAddress(Long branchId) {
        Query query = entityManager.createQuery("SELECT ba FROM Address ba, Branch b where b.id =:branchId AND b.branchAddress = ba");
        query.setParameter("branchId", branchId);
        return (AddressEntity) query.getSingleResult();
    }

    public FnBBranchEntity viewFnBBranch(Long branchId) {
        Query query = entityManager.createQuery("SELECT fnbb FROM FnBBranch fnbb, Branch b where b.id =:branchId AND b = fnbb");
        query.setParameter("branchId", branchId);
        return (FnBBranchEntity) query.getSingleResult();
    }

    public List<OperatingHoursEntity> viewBranchOperatingHours(Long branchId) {
        Query query = entityManager.createQuery("SELECT b FROM OperatingHour b where b.branch.id =:branchId and b.id NOT IN (select ex.id from ExtendedOperatingHour ex)");
        query.setParameter("branchId", branchId);
        return query.getResultList();
    }

    public List<CuisineTypeEntity> viewCuisinePref(Long branchId) {
        Query query = entityManager.createQuery("SELECT c FROM CuisineType c, FnBBranch fnbB where fnbB.id =:branchId AND c.fnbBranch = fnbB");
        query.setParameter("branchId", branchId);
        return query.getResultList();
    }

    public List<ExtendedOperatingHoursEntity> viewExtendedOperatingHours(Long branchId) {
        Query query = entityManager.createQuery("SELECT ex FROM ExtendedOperatingHour ex, OperatingHour ohe where ohe.branch.id =:branchId AND ohe = ex");
        query.setParameter("branchId", branchId);
        return query.getResultList();
    }

    public OperatingHoursRemarksEntity viewOperatingHoursRemarks(String locale, Long branchId) {
        Query query = entityManager.createQuery("SELECT ohr FROM OperatingHoursRemarks ohr where ohr.branch.id =:branchId AND ohr.locale =:locale");
        query.setParameter("branchId", branchId);
        query.setParameter("locale", locale);
        if (query.getResultList().isEmpty()) {
            OperatingHoursRemarksEntity emptyClass = new OperatingHoursRemarksEntity();
            emptyClass.setLocale("");
            emptyClass.setRemarks("");
            return emptyClass;
        } else {
            return (OperatingHoursRemarksEntity) query.getSingleResult();
        }
    }

    public boolean validateBranchName(String branchName) {
        Query query = entityManager.createQuery("SELECT fnbb FROM FnBBranch fnbb where fnbb.branchName =:branchName");
        query.setParameter("branchName", branchName);
        if (query.getResultList().size() != 0) {
            return false;
        }
        return true;
    }
}
